<!--
 * @Author: aster lipian1004@163.com
 * @Date: 2025-07-31 13:40:33
 * @FilePath: \easy-flowable-vue\src\views\workflow\components\render\html.vue
 * @Description: html
 * Copyright (c) 2025 by Aster, All Rights Reserved.
-->
<template>
  <div v-if="!_hidden">
    <el-form-item
      v-if="mode != 'print'"
      :prop="formItemProp"
      :label-width="labelWidth"
      :show-message="showMessage"
    >
      <template #label>
        <span v-show="_showLabel" style="line-height: normal">{{ formItem.title }}</span>
      </template>
      <div v-if="mode === 'design'">
        <div v-html="_value" />
      </div>
      <div v-else-if="mode === 'form'" style="width: 100%">
        <div v-if="formItem.props.type === 'html'" v-html="_value" />
        <template v-else="formItem.props.type === 'iframe'">
          <div
            v-if="formItem.props.isRemote"
            ref="htmlDomRef"
            :style="{ width: '100%', height: formItem.props.height + 'px' }"
          ></div>
          <div
            v-else
            ref="htmlDomRef"
            :style="{ width: '100%', height: formItem.props.height + 'px' }"
          >
          </div>
        </template>
      </div>
      <span v-else-if="mode === 'search'"> HTML不支持查询 </span>
      <span v-else>
        {{ _value }}
      </span>
    </el-form-item>
    <div v-else class="print-cell" ref="printRef">
      <div class="print-cell-label" :style="{ height: printMaxHeight + 'px' }">
        <p ref="printLabelRef" v-show="_showLabel">{{ formItem.title }}</p>
      </div>
      <div class="print-cell-value" :style="{ height: printMaxHeight + 'px' }">
        <p ref="printValueRef">{{ _value }}</p>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
  import { evaluateFormula } from '@/utils/workflow';
  import { computed, nextTick, onMounted, PropType, ref, watch } from 'vue';
  import mittBus from '@/utils/mittBus';
  import { isEmpty, isNotEmpty } from '@/utils';
  import { FormPermissionEnum } from '@/enums/workFlowEnum';

  const emit = defineEmits(['update:value']);
  const props = defineProps({
    value: {
      type: String,
      default: '',
    },
    mode: {
      type: String as PropType<'design' | 'form' | 'search' | 'table' | 'print'>,
      default: 'design',
    },
    formData: {
      type: Object as PropType<WorkForm.FormDataModel>,
      default: {},
    },
    formItem: {
      type: Object as PropType<WorkComponent.ComponentConfig>,
      default: {},
    },
    tableId: {
      type: String,
      default: '',
    },
    tableIndex: {
      type: Number,
      default: 0,
    },
    showLabel: {
      type: Boolean,
      default: true,
    },
  });

  // 注册组件
  const htmlDomRef = ref();

  let iframeDoc;

  // 打印 宽度
  const printRef = ref();
  const printLabelRef = ref();
  const printValueRef = ref();
  const printMaxHeight = ref(32);

  /**
   * @description: 更新高度
   */
  const updateHeight = () => {
    const parentHeight = printRef.value.parentNode?.offsetHeight;
    const labelHeight = printLabelRef.value?.offsetHeight;
    const valueHeight = printValueRef.value?.offsetHeight;
    printMaxHeight.value = Math.max(parentHeight, labelHeight, valueHeight);
  };

  // 是否远程调用
  const _isRemote = computed(() => {
    return props.formItem.props.type === 'iframe' && props.formItem.props.isRemote;
  });

  // 是否显示标签
  const _showLabel = computed(() => {
    return props.showLabel && !props.formItem.props.hiddenName;
  });

  // 键
  const formItemProp = computed(() => {
    if (isNotEmpty(props.tableId)) {
      return props.tableId + '.' + props.tableIndex + '.' + props.formItem.id;
    } else {
      return props.formItem.id;
    }
  });

  // 标签长度
  const labelWidth = computed(() => {
    if (!_showLabel.value) {
      return '12px';
    } else {
      return '';
    }
  });

  // 是否显示校验信息
  const showMessage = computed(() => {
    if (isNotEmpty(props.tableId)) {
      return false;
    } else {
      return true;
    }
  });

  /**
   * @description: 组件值
   */
  const _value = computed(() => {
    if (isEmpty(props.formItem.props.code)) {
      return '<div style="font-size: small; color: #9b9595">--请配置html代码--</div>';
    } else {
      return props.formItem.props.code;
    }
  });

  /**
   * @description: 监听表单数据变化
   */
  const _formData = computed(() => {
    return JSON.parse(JSON.stringify(props.formData));
  });

  /**
   * @description: 是否隐藏, true-隐藏
   */
  const _hidden = computed(() => {
    let r = false;
    // 解析隐藏条件公式
    if (props.formItem.props.hidden) {
      let expression = props.formItem.props.hidden;
      // 如果是子表中的控件，则需要用到下标
      if (isNotEmpty(props.tableId)) {
        expression = expression.replaceAll('?', props.tableIndex);
      }
      r = evaluateFormula(expression, props.formData);
    }
    // 判断流程节点下该控件是否隐藏
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.HIDDEN;
    }
    // 如果是必填则动态添加rule
    if (props.formItem.props.required) {
      // 调用form-render的方法
      mittBus.emit('changeFormRules', {
        hidden: r,
        fieldId: isNotEmpty(props.tableId)
          ? props.tableId + '.' + props.tableIndex + '.' + props.formItem.id
          : props.formItem.id,
        fieldName: props.formItem.title,
        trigger: 'blur',
      });
    }
    return r;
  });

  /**
   * @description: 监听打印高度
   */
  watch(
    () => [props.mode, printRef.value],
    () => {
      if (printRef.value && props.mode === 'print') {
        updateHeight();
      }
    },
    { immediate: true, deep: true },
  );

  /**
   * 验证远程URL
   */
  const validateRemote = (url: string) => {
    if (url && isNotEmpty(url)) {
      try {
        new URL(url);
        return true;
      } catch (e) {
        // 特殊处理相对路径
        if (url.startsWith('/')) {
          return true;
        }
        return false;
      }
    }
    return false;
  };

  /**
   * 设置参数
   */
  const setParams = (url: string, params: WorkComponent.UrlParams[]) => {
    try {
      // 处理相对路径（以/开头），基于当前域名构建完整URL
      const fullUrl = url.startsWith('/') ? new URL(url, window.location.origin) : new URL(url);

      // 记录原始路径是否为空（用于纯域名情况）
      const isOriginalPathEmpty = fullUrl.pathname === '/' && !fullUrl.search && !fullUrl.hash;

      // 如果存在哈希部分，处理Vue的hash模式路由
      if (fullUrl.hash && params?.length) {
        let hashPath = fullUrl.hash.substring(1);
        const tempUrl = new URL(`http://example.com`);
        tempUrl.pathname = hashPath;

        params.forEach((param) => {
          if (param.key && param.value !== undefined && !param.value.startsWith('field')) {
            tempUrl.searchParams.set(param.key, param.value);
          }
        });

        fullUrl.hash = tempUrl.pathname + tempUrl.search;
      } else if (params?.length) {
        // 没有哈希部分的情况，添加到URL参数
        params.forEach((param) => {
          if (param.key && param.value !== undefined && !param.value.startsWith('field')) {
            fullUrl.searchParams.set(param.key, param.value);
          }
        });
      }

      let resultUrl = fullUrl.toString();

      // 特殊处理：纯域名且添加了参数的情况，移除多余的斜杠
      if (isOriginalPathEmpty && params?.length) {
        resultUrl = resultUrl.replace('/?', '?');
      }
      // 新增：添加随机时间戳参数，避免缓存
      const timestamp = new Date().getTime();
      resultUrl += (resultUrl.includes('?') ? '&' : '?') + `_t=${timestamp}`;
      return resultUrl;
    } catch (e) {
      console.error('URL解析错误:', e);
      return url;
    }
  };

  /**
   * @description: 处理iframe远程参数
   */
  const handleRemoteParams = () => {
    // 查找 linkage 类型的参数
    const linkageParams = props.formItem.props.remoteParams.filter(
      (param) => param.type === 'linkage' && param.key && param.value,
    );
    // 如果存在 linkage 参数，则更新 iframe 的 src
    if (linkageParams.length > 0 && htmlDomRef.value) {
      const iframe = htmlDomRef.value.querySelector('iframe');
      if (iframe) {
        // 构造新的参数列表，将 linkage 参数替换为实际表单值
        const processedParams = props.formItem.props.remoteParams.map((param) => {
          if (param.type === 'linkage' && param.value) {
            return {
              ...param,
              value: props.formData[param.value] ?? '',
            };
          }
          return param;
        });

        const newSrc = setParams(props.formItem.props.code, processedParams);
        console.log('iframe-newSrc--->', newSrc);
        // 强制刷新：先清空再赋值
        iframe.src = 'about:blank';
        // 用setTimeout确保顺序执行
        setTimeout(() => {
          iframe.src = newSrc;
        }, 500);
      }
    }
  };

  watch(
    () => _formData.value,
    () => {
      // 判断是否有联动参数
      const shouldProcessLinkage =
        _formData.value &&
        htmlDomRef.value &&
        props.formItem.props.type === 'iframe' &&
        props.formItem.props.isRemote &&
        Array.isArray(props.formItem.props.remoteParams) &&
        props.formItem.props.remoteParams.length > 0;

      if (!shouldProcessLinkage) {
        return;
      }
      // 有则处理联动参数
      handleRemoteParams();
    },
    { immediate: true, deep: true },
  );

  /**
   * @description: 创建iframe
   */
  const createIframe = () => {
    // 创建 iframe 元素
    const iframe = document.createElement('iframe');
    iframe.id = new Date().getTime() + '';
    iframe.style.width = '100%';
    iframe.style.height = '100%';
    // iframe.style.height = '500px'; // 根据需要调整高度
    iframe.style.border = 'none';
    // 将 iframe 添加到容器中
    htmlDomRef.value.appendChild(iframe);
    if (_isRemote.value && validateRemote(props.formItem.props.code)) {
      if (
        Array.isArray(props.formItem.props.remoteParams) &&
        props.formItem.props.remoteParams.length > 0
      ) {
        handleRemoteParams();
      } else {
        iframe.src = props.formItem.props.code;
      }
      console.log('createIframe', iframe.src);
    } else {
      // 获取 iframe 的文档对象
      iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
      // 写入 HTML 字符串
      iframeDoc.open();
      iframeDoc.write(_value.value);
      iframeDoc.close();
    }
  };

  onMounted(() => {
    console.log('onMounted');
    if (props.mode === 'form' && props.formItem.props.type === 'iframe') {
      createIframe();
    }
  });

  defineExpose({
    _hidden,
  });
</script>
<style scoped lang="scss">
  @import url(../print/print.scss);
</style>
